package com.vhall.component.service.interactive.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.vhall.component.dao.account.AccountMapper;
import com.vhall.component.entity.account.AccountEntity;
import com.vhall.component.entity.interactive.entity.QuestionsEntity;
import com.vhall.component.entity.interactive.vo.*;
import com.vhall.component.entity.room.RoomQuestionLkEntity;
import com.vhall.component.entity.room.dto.RoomsEntityDTO;
import com.vhall.component.framework.common.exception.BusinessException;
import com.vhall.component.framework.common.utils.CollectionUtils;
import com.vhall.component.plugin.common.constant.RedisKey;
import com.vhall.component.plugin.common.exception.BizErrorCode;
import com.vhall.component.plugin.common.support.Token;
import com.vhall.component.plugin.common.support.TokenThreadLocal;
import com.vhall.component.service.interactive.QuestionCacheService;
import com.vhall.component.service.interactive.QuestionConsoleService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author guoxin.wang
 * @date 2021-06-10 15:21
 */
@Slf4j
@Service
public class QuestionConsoleServiceImpl extends QuestionBaseServiceImpl implements QuestionConsoleService {


    @Value("${paas.apps.lite.appId}")
    public String appId;


    @Autowired
    private QuestionCacheService questionCacheService;
    @Autowired
    private AccountMapper accountMapper;


    @Override
    public QuestionPage<QuestionConsoleLinkRoomListRspVO> linkRoomList(QuestionConsoleLinkRoomListReqVO reqVO) {
        List<QuestionConsoleLinkRoomListRspVO> resultOfList = new ArrayList<>();
        // 1、根据token获取用户信息。
        Token account = TokenThreadLocal.getToken();
        Integer page = reqVO.getPage();
        Integer pageSize = reqVO.getPageSize();
        reqVO.setAccountId(String.valueOf(account.getAccountId()));
        // 2.1、如果存在question id的话就查询该问卷关联的房间号。
        QuestionConsoleLinkRoomListRspVO roomOfLinked = null;
        if (StringUtils.isNotBlank(reqVO.getQuestionId())) {
            roomOfLinked = questionRoomMapper.selectRoomInfoByQuestionId(reqVO);

        }
        // 2.2、查询房间信息，如果存在关联的就吧每页数量减一。并且不查询关联的房间信息。
        Integer startIndex = (page - 1) * reqVO.getPageSize();
        if (roomOfLinked != null) {
            if ("1".equals(String.valueOf(page))) {
                resultOfList.add(roomOfLinked);
                roomOfLinked.setIsLinkRoom(1);
                pageSize -= 1;
                reqVO.setPageSize(pageSize);
            } else {
                startIndex--;
            }
        }
        List<QuestionConsoleLinkRoomListRspVO> roomOfExclusiveLinkedPaged = questionRoomMapper
                .selectRoomInfoExclusiveLinkedPaged(reqVO, roomOfLinked, startIndex);
        if (CollectionUtils.isNotEmpty(roomOfExclusiveLinkedPaged)) {
            for (QuestionConsoleLinkRoomListRspVO single : roomOfExclusiveLinkedPaged) {
                single.setIsLinkRoom(0);
            }
            resultOfList.addAll(roomOfExclusiveLinkedPaged);
        }
        Integer count = questionRoomMapper.selectCountOfRoomInfoExclusiveLinkedPaged(reqVO, roomOfLinked);
        if (roomOfLinked != null) {
            count++;
        }
        return new QuestionPage<>(reqVO.getPage(), reqVO.getPageSize(), count, resultOfList);
    }

    @Override
    public QuestionConsoleCreateRspVO create(QuestionConsoleCreateReqVO reqVO) {
        // 1、查询room信息。
        RoomsEntityDTO roomInfo = roomInnerService.getRoomInfo(reqVO.getRoomId());
        if (ObjectUtil.isEmpty(roomInfo)) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        // 2、根据token获取用户信息。
        Token account = TokenThreadLocal.getToken();
        // 3、同步至vss。
        reqVO.setAccountId(String.valueOf(account.getAccountId()));
        reqVO.setExtend("");
        reqVO.setCover(reqVO.getImgUrl());
        reqVO.setAppId(appId);
        // 校验一下room id的格式是否正确，和room id对应的room是否存在。
        roomInnerService.checkRoomId(roomInfo.getRoomId());
        // 校验一下参数里的account id和room里的account id是否相等。
        if (reqVO.getAccountId() == null || !String.valueOf(reqVO.getAccountId()).equals(String.valueOf(roomInfo.getAccountId()))) {
            log.error("参数中的account id和room中的account id不匹配！:{}{}", reqVO.getAccountId(), roomInfo.getAccountId());
            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
        }
        // 根据question id查询，如果有的话更新，没有的话新增。
        QuestionsEntity qeOfDb = questionsMapper.selectByQuestionId(reqVO.getQuestionId());
        QuestionsEntity qe = new QuestionsEntity();
        try {
            if (qeOfDb != null) {
                // 更新操作
                BeanUtils.copyProperties(reqVO, qe);
                qe.setQuestionId(reqVO.getQuestionId());
                qe.setUpdatedAt(LocalDateTime.now());
                questionsMapper.updateById(qe);
            } else {
                // 新增操作,, question id永远都会从前台穿过来
                BeanUtils.copyProperties(reqVO, qe);
                qe.setQuestionId(reqVO.getQuestionId());
                qe.setCreatedAt(LocalDateTime.now());
                qe.setUpdatedAt(LocalDateTime.now());
                questionsMapper.insert(qe);
            }
            qeOfDb = questionsMapper.selectByQuestionId(reqVO.getQuestionId());
            // 3.5、绑定信息
            boolean flag = bindRoom(reqVO.getQuestionId(), Integer.valueOf(String.valueOf(account.getAccountId())), roomInfo.getRoomId(), null);
            if (!flag) {
                throw new BusinessException(BizErrorCode.COMP_QUESTION_BIND_ROOM_FAILED);
            }
        } finally {
            // 清空房间缓存的问卷信息
            questionCacheService.deleteCachedQuestionDetailData(roomInfo.getRoomId());
        }

        // 4、查询一下问卷信息。
        QuestionConsoleCreateRspVO qrv = new QuestionConsoleCreateRspVO();
        qrv.setQId(qeOfDb.getQuestionId());
        qrv.setQuestionId(qeOfDb.getQuestionId());
        qrv.setTitle(qeOfDb.getTitle());
        qrv.setDescription(qeOfDb.getDescription());
        qrv.setCover(qeOfDb.getCover());
        qrv.setExtend(qeOfDb.getExtend());
        qrv.setAccountId(Integer.parseInt(qeOfDb.getAccountId()));
        qrv.setSourceId(String.valueOf(qeOfDb.getSourceId()));
        qrv.setIsPublic(String.valueOf(qeOfDb.getIsPublic()));
        qrv.setCreatedAt(String.valueOf(qeOfDb.getCreatedAt()));
        qrv.setUpdatedAt(String.valueOf(qeOfDb.getUpdatedAt()));
        qrv.setAppId(String.valueOf(qeOfDb.getAppId()));
        return qrv;
    }

    @Override
    public QuestionPage<QuestionConsoleListRspVO> list(QuestionConsoleListReqVO reqVO) {
        List<QuestionConsoleListRspVO> result = new ArrayList<>();
        // 1、根据token获取用户信息。
        Token accountInfo = TokenThreadLocal.getToken();
        // 2、查询问卷信息。
        QuestionsEntity param = new QuestionsEntity();
        List<Integer> accountIds = null;
        if (accountInfo.getRoleType() == 1) {
            // 平台级
            param.setAccountId(null);
        } else {
            // 部门级
            LambdaQueryWrapper<AccountEntity> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(AccountEntity::getOrgCode, accountInfo.getOrgCode());
            List<AccountEntity> accountEntities = accountMapper.selectList(queryWrapper);
            accountIds = accountEntities.stream().map(AccountEntity::getAccountId).collect(Collectors.toList());
        }

        String keyword = reqVO.getKeyword();
        Integer startIndex = (reqVO.getPage() - 1) * reqVO.getPageSize();
        List<QuestionConsoleListRspVO> list = questionRoomMapper.selectQuestionInfo(param, keyword, accountIds, startIndex, reqVO.getPageSize());
        Integer count = questionRoomMapper.selectCountOfQuestionInfo(param, keyword, accountIds, startIndex, reqVO.getPageSize());
        if (CollectionUtils.isEmpty(list)) {
            return new QuestionPage<>(reqVO.getPage(), reqVO.getPageSize(), count, result);
        }
        result.addAll(list);
        // 3、查询问卷的填写人数。
        List<QuestionCountVo> counts;
        Map<Integer, Integer> mapOfCount = new HashMap<>(16);
        Map<String, Integer> mapOfAccount = new HashMap<>(16);
        Map<String, RoomsEntityDTO> mapOfRoomInfo = new HashMap<>(16);
        List<Integer> questionIds = list.stream().map(QuestionConsoleListRspVO::getQuestionId).collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(questionIds)) {
            counts = questionAnswersMapper.getAnswerCountByQuestionIds(questionIds);
            for (QuestionCountVo v : counts) {
                mapOfCount.put(v.getQuestionId(), v.getCount());
            }
            // 4、查询当前用户是否填写了问卷。  主持人会填写发布的问卷吗？
//            accounts = questionAnswersMapper.getWhetherMap(questionIds, accountInfo.getAccountId());
//            for (QuestionCountVo v : accounts) {
//                mapOfAccount.put(String.valueOf(v.getQuestionId()), v.getAnswerId());
//            }
        }

        // 给集合中的ilId赋值。
        List<String> roomIds = new ArrayList<>();
        for (QuestionConsoleListRspVO qpl : list) {
            if (qpl.getRoomId() != null && StringUtils.isNotBlank(qpl.getRoomId())) {
                roomIds.add(qpl.getRoomId());
            }
        }
        if (CollectionUtils.isNotEmpty(roomIds)) {
            List<RoomsEntityDTO> rooms = roomInnerService.getRoomInfoByRoomIds(roomIds);
            if (CollectionUtils.isNotEmpty(rooms)) {
                for (RoomsEntityDTO re : rooms) {
                    mapOfRoomInfo.put(re.getRoomId(), re);
                }
            }
        }
        // 5、给集合中的数据赋值。
        for (QuestionConsoleListRspVO qpl : list) {
            qpl.setAnswererCount(mapOfCount.getOrDefault(qpl.getQuestionId(), 0));
            if (mapOfAccount.containsKey(String.valueOf(qpl.getQuestionId()))) {
                qpl.setIsFill("1");
                qpl.setAnswerId(String.valueOf(mapOfAccount.get(String.valueOf(qpl.getQuestionId()))));
            } else {
                qpl.setIsFill("0");
                qpl.setAnswerId("0");
            }
            if (mapOfRoomInfo.containsKey(qpl.getRoomId())) {
                qpl.setIlId(String.valueOf(mapOfRoomInfo.get(qpl.getRoomId()).getIlId()));
            }
            if (qpl.getBindAccountId() != null) {
                AccountEntity accountEntity = accountMapper.selectById(qpl.getAccountId());
                if (accountEntity != null) {
                    qpl.setCreatedBy(accountEntity.getNickname());
                }

            }
        }
        return new QuestionPage<>(reqVO.getPage(), reqVO.getPageSize(), count, result);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> delete(QuestionConsoleDeleteReqVO reqVO) {
        List<String> result = new ArrayList<>();
        // 1、根据token获取用户信息。
        Token account = TokenThreadLocal.getToken();
        if (account.getAccountId() == null) {
            throw new BusinessException(BizErrorCode.COMP_QUESTION_ACCOUNT_INFO_NO_ID);
        }
        // 2、处理一下参数。
        String[] arr = reqVO.getQuestionIds().split(",");
        List<String> questionIds = Arrays.asList(arr);
        // 3、执行删除操作。
        QuestionConsoleCreateReqVO qe = new QuestionConsoleCreateReqVO();
        for (String questionId : questionIds) {
            // 先查询出来判断下是否被发布了。
            try {
                qe.setQuestionId(Integer.valueOf(questionId));
            } catch (NumberFormatException e) {
                throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
            }
            QuestionsEntity questionsEntity = questionsMapper.selectByQuestionId(qe.getQuestionId());
            if (questionsEntity != null) {
                // 在这里添加校验，如果不是自己的问卷不允许删除。
//                if (!questionsEntity.getAccountId().equals(String.valueOf(account.getAccountId()))) {
//                    throw new BusinessException(BizErrorCode.COMP_QUESTION_NO_DELETE_ABILITY);
//                }
                Integer id = roomQuestionLkMapper.questionIsPublish(Integer.valueOf(questionId));
                if (id == null) {
                    // 还没发布，可以删除。
                    // 设置为逻辑删除。
                    LambdaUpdateWrapper<QuestionsEntity> whereOfLk = Wrappers.lambdaUpdate();
                    whereOfLk.eq(QuestionsEntity::getQuestionId, questionId);
                    QuestionsEntity lkParam = new QuestionsEntity();
                    lkParam.setDeletedAt(LocalDateTime.now());
                    int rowEffect = questionsMapper.update(lkParam, whereOfLk);
                    if (rowEffect == 0) {
                        log.error("删除问卷：{}失败", reqVO.getQuestionIds());
                    } else {
                        result.add(questionId);
                    }
                } else {
                    throw new BusinessException(BizErrorCode.COMP_QUESTION_NOT_DELETE);
                }
            } else {
                throw new BusinessException(BizErrorCode.EMPTY_QUESTION);
            }
        }
        return result;
    }

    @Override
    public String publish(QuestionConsolePublishReqVO reqVO) {
        // 1、根据token获取用户信息。
        Token account = TokenThreadLocal.getToken();
        // 1.5、用户信息是存在的，所以直接设置角色名称。
        Integer roleName = 1;
        doPublish(account.getAccountId(), account.getNickname(), reqVO.getRoomId(), reqVO.getQuestionId(), roleName);
        return "true";
    }

    @Override
    public QuestionConsoleCreateRspVO update(QuestionConsoleUpdateReqVO reqVO) {
        QuestionConsoleCreateRspVO result = new QuestionConsoleCreateRspVO();
        result.setQId(reqVO.getQuestionId());
        result.setQuestionId(reqVO.getQuestionId());
        // 1、根据token获取用户信息。
        Token account = TokenThreadLocal.getToken();
        // 2、获取房间信息。
        RoomsEntityDTO re = roomInnerService.getRoomInfo(reqVO.getRoomId());
        if (ObjectUtil.isEmpty(re)) {
            throw new BusinessException(BizErrorCode.EMPTY_ROOM);
        }
        // 3、校验一下用户信息里的account_id和room里的account_id是否相等。
//        if (!(StringUtils.isNotBlank(String.valueOf(account.getAccountId()))
//                && ObjectUtil.isNotEmpty(re.getAccountId())
//                && String.valueOf(account.getAccountId()).equals(String.valueOf(re.getAccountId())))) {
//            log.error("用户信息中的account_id和房间信息中的account_id不匹配！:{}{}", account.getAccountId(), re.getAccountId());
//            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
//        }
        // 4、查询问卷信息。
        QuestionConsoleCreateReqVO param = new QuestionConsoleCreateReqVO();
        param.setQuestionId(reqVO.getQuestionId());
        QuestionsEntity qe = questionsMapper.selectByQuestionId(param.getQuestionId());
        if (qe == null) {
            throw new BusinessException(BizErrorCode.EMPTY_QUESTION);
        }
        // 5、校验一下用户信息里的account id和问卷里的account id是否相等。
//        if (!(StringUtils.isNotBlank(String.valueOf(account.getAccountId()))
//                && ObjectUtil.isNotEmpty(qe.getAccountId())
//                && String.valueOf(account.getAccountId()).equals(String.valueOf(qe.getAccountId())))) {
//            log.error("用户信息中的account id和问卷信息中的account id不匹配！:{}{}", account.getAccountId(), qe.getAccountId());
//            throw new BusinessException(BizErrorCode.BIZ_INVALID_PARAM);
//        }
        // 6、执行更新问卷操作，注意已经发布的不允许更新。
        Integer updateFlag = roomQuestionLkMapper.questionIsPublish(reqVO.getQuestionId());
        if (updateFlag != null) {
            // 已经发布了。
            log.error("问卷id为{}的问卷已经发布，不允许修改！", reqVO.getQuestionId());
            throw new BusinessException(BizErrorCode.COMP_QUESTION_NOT_EDIT);
        }
        try {
            LambdaUpdateWrapper<QuestionsEntity> whereOfQ = Wrappers.lambdaUpdate();
            whereOfQ.eq(QuestionsEntity::getQuestionId, reqVO.getQuestionId());
            QuestionsEntity qeParam = new QuestionsEntity();
            BeanUtils.copyProperties(reqVO, qeParam);
            qeParam.setQuestionId(reqVO.getQuestionId());
            qeParam.setUpdatedAt(LocalDateTime.now());
            int update = questionsMapper.update(qeParam, whereOfQ);
            if (update <= 0) {
                throw new BusinessException(BizErrorCode.COMP_QUESTION_UPDATE_FAILED);
            }
            // 7、更新绑定的room的操作。
            LambdaQueryWrapper<RoomQuestionLkEntity> whereOfRqle = Wrappers.lambdaQuery();
            whereOfRqle.eq(RoomQuestionLkEntity::getQuestionId, reqVO.getQuestionId())
                    .last("limit 1");
            RoomQuestionLkEntity rqOfOld = roomQuestionLkMapper.selectOne(whereOfRqle);
            if (rqOfOld == null) {
                // 执行创建操作。
                bindRoom(reqVO.getQuestionId(), Integer.valueOf(String.valueOf(account.getAccountId())), re.getRoomId(), null);
                return result;
            } else {
                // 执行更新操作。
                LambdaUpdateWrapper<RoomQuestionLkEntity> whereOfLk = Wrappers.lambdaUpdate();
                whereOfLk.eq(RoomQuestionLkEntity::getQuestionId, reqVO.getQuestionId());
                RoomQuestionLkEntity lkParam = new RoomQuestionLkEntity();
                lkParam.setRoomId(re.getRoomId());
                lkParam.setBind(1);
                lkParam.setUpdatedAt(LocalDateTime.now());
                int updateFlagOfLk = roomQuestionLkMapper.update(lkParam, whereOfLk);
                if (updateFlagOfLk <= 0) {
                    throw new BusinessException(BizErrorCode.COMP_QUESTION_PUBLISH_FAILED);
                }
            }
            // 8、删除缓存。
            redisTemplate.delete(RedisKey.QUESTION_INFO_KEY + rqOfOld.getRoomId() + "and" + reqVO.getQuestionId());
        } finally {
            // 清空房间缓存的问卷信息
            questionCacheService.deleteCachedQuestionDetailData(re.getRoomId());
        }
        return result;
    }

    @Override
    public QuestionLogPage<QuestionConsoleLogRspVO> getQuestionLog(QuestionConsoleLogReqVO req) {
        List<QuestionConsoleLogRspVO> result = new ArrayList<>();
        Integer count = 0;
        // 1、根据token获取用户信息。
        Token accountInfo = TokenThreadLocal.getToken();
        req.setAccountId(String.valueOf(accountInfo.getAccountId()));
        // 2、开始查询--其实就是根据questionid还有roomid分组，然后求一下和。
        Integer startIndex = (req.getPage() - 1) * req.getPageSize();
        req.setStartIndex(startIndex);
        if (StrUtil.isNotEmpty(req.getBeginTime())) {
            req.setBeginTime(req.getBeginTime() + " 00:00:00");
        }
        if (StrUtil.isNotEmpty(req.getEndTime())) {
            req.setEndTime(req.getEndTime() + " 23:59:59");
        }
        if (StringUtils.isBlank(req.getRoomId())) {
            // 这里先查询count最好。可以哪来做判断，减少一次查询数据库的操作。
            count = questionAnswersMapper.accountStatisticsListForCount(req);
            if (count > 0) {
                List<QuestionConsoleLogRspVO> list = questionAnswersMapper.accountStatisticsList(req);
                count = list.size();
                List<String> roomIdArr;
                if (!list.isEmpty()) {
                    roomIdArr = list.stream().map(QuestionConsoleLogRspVO::getRoomId).collect(Collectors.toList());
                    if (!roomIdArr.isEmpty()) {
                        List<RoomsEntityDTO> roomInfoByRoomIds = roomInnerService.getRoomInfoByRoomIds(roomIdArr);
                        if (roomInfoByRoomIds != null && !roomInfoByRoomIds.isEmpty()) {
                            Map<String, String> roomMap = new HashMap<>(16);
                            for (RoomsEntityDTO roomsEntity : roomInfoByRoomIds) {
                                roomMap.put(roomsEntity.getRoomId(), String.valueOf(roomsEntity.getIlId()));
                            }
                            for (QuestionConsoleLogRspVO single : list) {
                                single.setIlId(roomMap.getOrDefault(single.getRoomId(), ""));
                            }
                        }
                    }
                    result.addAll(list);
                }
            }
        } else {
            RoomsEntityDTO roomInfo = roomInnerService.getRoomInfo(req.getRoomId());
            if (roomInfo == null) {
                return new QuestionLogPage<>(req.getPage(), req.getPageSize(), 0, result);
            }
            req.setRoomId(roomInfo.getRoomId());
            // 这里先查询count最好。可以哪来做判断，减少一次查询数据库的操作。
            count = questionAnswersMapper.accountStatisticsListForCount(req);
            if (count > 0) {
                List<QuestionConsoleLogRspVO> list = questionAnswersMapper.accountStatisticsList(req);
                if (list != null && !list.isEmpty()) {
                    for (QuestionConsoleLogRspVO single : list) {
                        single.setIlId(roomInfo.getIlId().toString());
                        single.setRoomId(roomInfo.getRoomId());
                        if (single.getAnswerCount() == null) {
                            single.setAnswerCount(0);
                        }
                    }
                    result.addAll(list);
                }
            }
        }
        return new QuestionLogPage<>(req.getPage(), req.getPageSize(), count, result);
    }

}
